/*-------------------------------------------------------------------------
 *
 * old_snapshot.h
 *		“快照太旧”的数据结构。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *	  src/include/utils/old_snapshot.h
 *
 *-------------------------------------------------------------------------
 */

#ifndef OLD_SNAPSHOT_H
#define OLD_SNAPSHOT_H

#include "datatype/timestamp.h"
#include "storage/s_lock.h"

/*
 * 处理old_snapshot_threshold实现的结构。
 */
typedef struct OldSnapshotControlData
{
	/*
	 * 旧快照处理的变量在进程之间共享，并且只能向前移动。
	 */
	slock_t		mutex_current;	/* 保护current_timestamp */
	TimestampTz current_timestamp;	/* 最新的快照时间戳 */
	slock_t		mutex_latest_xmin;	/* 保护latest_xmin和next_map_update */
	TransactionId latest_xmin;	/* 最新的快照xmin */
	TimestampTz next_map_update;	/* 最新的快照有效至 */
	slock_t		mutex_threshold;	/* 保护阈值字段 */
	TimestampTz threshold_timestamp;	/* 早期快照是旧的 */
	TransactionId threshold_xid;	/* 早期的 xid 可能已经不存在 */

	/*
	 * 每分钟保留一个 xid 以处理旧快照错误。
	 *
	 * 使用一个带有头偏移、当前使用条目计数和与头偏移对应的 xid 时间戳的循环缓冲区。
	 * count_used 值为零表示没有存储的时间；count_used 值为 OLD_SNAPSHOT_TIME_MAP_ENTRIES 表示缓冲区已满，头部必须向前移动以添加新条目。
	 * 使用对齐到分钟边界的时间戳，因为这看起来比根据第一次使用时间戳对齐更不令人惊讶。
	 * 最新的桶实际上存储在 latest_xmin 中。当我们获得一个新 xmin 值时，如果它不属于同一时间段，则更新循环缓冲区。
	 *
	 * 如果给定时间段的 xid 早于通过将与头偏移到头条目的时间相对应的分钟数（可能是环绕的距离）来计算的时间，这也是可以的，
	 * 因为这只是导致旧元组的清理稍微不那么积极。它如果在另一个方向偏差就不可以了，因为这可能导致清理仍然预计存在的元组。
	 *
	 * 考虑过使用 SLRU 但没有选择，因为其比这一需求重，并且实现的代码可能不会少。
	 *
	 * 不需要持久性。
	 */
	int			head_offset;	/* 最旧跟踪时间的下标 */
	TimestampTz head_timestamp; /* 与头 xid 对应的时间 */
	int			count_used;		/* 使用中的槽位数量 */
	TransactionId xid_by_minute[FLEXIBLE_ARRAY_MEMBER];
} OldSnapshotControlData;

extern PGDLLIMPORT volatile OldSnapshotControlData *oldSnapshotControl;

#endif
